package com.cby.operation.common.widget.floatview

import android.R
import android.app.Activity
import android.content.Context
import android.graphics.PixelFormat
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.view.WindowManager.BadTokenException
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView

/**
 * Description:HykbFloatView
 *
 * @author 陈宝阳
 * @create 2019/12/30 14: 48
 */
class HykbFloatView private constructor(
    /** 上下文  */
    private val mContext: Context
) {
    /** 根布局  */
    private var mRootView: View? = null

    /** 悬浮窗口  */
    private val mWindowManager: WindowManager

    /** 窗口参数  */
    private val mWindowParams: WindowManager.LayoutParams?
    /**
     * 当前是否已经显示
     */
    /** 当前是否已经显示  */
    var isShow = false
        private set

    /** 窗口显示时长  */
    private var mDuration = 0

    /**
     * 创建一个局部悬浮窗
     */
    constructor(activity: Activity) : this(activity as Context) {

        // 如果当前 Activity 是全屏模式，那么添加这个标记，否则会导致 WindowManager 在某些机型上移动不到状态栏位置上
        if (activity.window.attributes.flags and WindowManager.LayoutParams.FLAG_FULLSCREEN != 0) {
            addWindowFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
        }
    }

    /**
     * 设置动画样式
     */
    fun setAnimStyle(id: Int): HykbFloatView {
        mWindowParams!!.windowAnimations = id
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 添加一个标志位
     */
    fun addWindowFlags(flags: Int): HykbFloatView {
        mWindowParams!!.flags = mWindowParams.flags or flags
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 是否有这个标志位
     */
    fun hasWindowFlags(flags: Int): Boolean {
        return mWindowParams!!.flags and flags != 0
    }

    /**
     * 移除一个标志位
     */
    fun removeWindowFlags(flags: Int): HykbFloatView {
        mWindowParams!!.flags = mWindowParams.flags and flags.inv()
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 根据 ViewId 获取 View
     */
    fun <V : View?> findViewById(id: Int): V {
        checkNotNull(mRootView) { "Please setup view" }
        return mRootView!!.findViewById<View>(id) as V
    }

    fun setText(viewId: Int, stringId: Int): HykbFloatView {
        return setText(viewId, mContext.resources.getString(stringId))
    }

    fun setText(text: CharSequence?): HykbFloatView {
        return setText(R.id.message, text)
    }

    fun setText(id: Int, text: CharSequence?): HykbFloatView {
        (findViewById<View>(id) as TextView).text = text
        return this
    }

    fun setVisible(viewId: Int, visibility: Int): HykbFloatView {
        findViewById<View>(viewId).visibility = visibility
        return this
    }

    /**
     * 设置点击事件
     */
    fun <T: View> setOnClickListener(id: Int, listener: OnClickListener<T>): HykbFloatView {
        ViewClickWrapper<T>(this, findViewById(id), listener)
        // 当前是否设置了不可触摸，如果是就擦除掉
        if (hasWindowFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)) {
            removeWindowFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
            if (isShow) {
                update()
            }
        }
        return this
    }

    /**
     * 设置 X 轴偏移量
     */
    fun setXOffset(x: Int): HykbFloatView {
        mWindowParams!!.x = x
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 设置 Y 轴偏移量
     */
    fun setYOffset(y: Int): HykbFloatView {
        mWindowParams!!.y = y
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 设置重心
     */
    fun setGravity(gravity: Int): HykbFloatView {
        mWindowParams!!.gravity = gravity
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 设置宽度
     */
    fun setWidth(width: Int): HykbFloatView {
        mWindowParams!!.width = width
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 设置高度
     */
    fun setHeight(height: Int): HykbFloatView {
        mWindowParams!!.height = height
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 限定显示时长
     */
    fun setDuration(duration: Int): HykbFloatView {
        mDuration = duration
        if (isShow) {
            if (mDuration != 0) {
                removeCallbacks()
                postDelayed(DismissRunnable(this), mDuration.toLong())
            }
        }
        return this
    }

    /**
     * 设置布局
     */
    fun setView(id: Int): HykbFloatView {
        return setView(LayoutInflater.from(mContext).inflate(id, FrameLayout(mContext), false))
    }

    fun setView(view: View?): HykbFloatView {
        mRootView = view
        val params = mRootView!!.layoutParams
        if (params != null && mWindowParams!!.width == WindowManager.LayoutParams.WRAP_CONTENT && mWindowParams.height == WindowManager.LayoutParams.WRAP_CONTENT) {
            // 如果当前 Dialog 的宽高设置了自适应，就以布局中设置的宽高为主
            setWidth(params.width)
            setHeight(params.height)
        }

        // 如果当前没有设置重心，就自动获取布局重心
        if (mWindowParams!!.gravity == Gravity.NO_GRAVITY) {
            if (params is FrameLayout.LayoutParams) {
                setGravity(params.gravity)
            } else if (params is LinearLayout.LayoutParams) {
                setGravity(params.gravity)
            } else {
                // 默认重心是居中
                setGravity(Gravity.CENTER)
            }
        }
        if (isShow) {
            update()
        }
        return this
    }

    /**
     * 显示
     */
    fun show(): HykbFloatView {
        require(!(mRootView == null || mWindowParams == null)) { "WindowParams and view cannot be empty" }

        // 如果当前已经显示取消上一次显示
        if (isShow) {
            cancel()
        }
        try {
            // 如果这个 View 对象被重复添加到 WindowManager 则会抛出异常
            // java.lang.IllegalStateException: View android.widget.TextView{3d2cee7 V.ED..... ......ID 0,0-312,153} has already been added to the window manager.
            mWindowManager.addView(mRootView, mWindowParams)
            // 当前已经显示
            isShow = true
            // 如果当前限定了显示时长
            if (mDuration != 0) {
                postDelayed(DismissRunnable(this), mDuration.toLong())
            }
        } catch (e: NullPointerException) {
            e.printStackTrace()
        } catch (e: IllegalStateException) {
            e.printStackTrace()
        } catch (e: BadTokenException) {
            e.printStackTrace()
        }
        return this
    }

    /**
     * 取消
     */
    fun cancel(): HykbFloatView {
        if (isShow) {
            try {


                // 如果当前 WindowManager 没有附加这个 View 则会抛出异常
                // java.lang.IllegalArgumentException: View=android.widget.TextView{3d2cee7 V.ED..... ........ 0,0-312,153} not attached to window manager
                mWindowManager.removeView(mRootView)
            } catch (e: NullPointerException) {
                e.printStackTrace()
            } catch (e: IllegalArgumentException) {
                e.printStackTrace()
            } catch (e: IllegalStateException) {
                e.printStackTrace()
            }
            // 当前没有显示
            isShow = false
        }
        return this
    }

    /**
     * 更新
     */
    fun update() {
        // 更新 WindowManger 的显示
        mWindowManager.updateViewLayout(mRootView, mWindowParams)
    }

    /**
     * 延迟一段时间执行
     */
    fun postDelayed(r: Runnable?, delayMillis: Long): Boolean {
        var delayMillis = delayMillis
        if (delayMillis < 0) {
            delayMillis = 0
        }
        return postAtTime(r, SystemClock.uptimeMillis() + delayMillis)
    }

    /**
     * 在指定的时间执行
     */
    fun postAtTime(r: Runnable?, uptimeMillis: Long): Boolean {
        // 发送和这个 WindowManager 相关的消息回调
        return HANDLER.postAtTime(r!!, this, uptimeMillis)
    }

    /**
     * 移除消息回调
     */
    fun removeCallbacks() {
        HANDLER.removeCallbacksAndMessages(this)
    }

    companion object {
        private val HANDLER = Handler(Looper.getMainLooper())
    }

    init {
        mWindowManager = mContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        mWindowParams = WindowManager.LayoutParams()
        // 配置一些默认的参数
        mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT
        mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT
        mWindowParams.format = PixelFormat.TRANSLUCENT
        mWindowParams.windowAnimations = R.style.Animation_Toast
        mWindowParams.flags = (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
        mWindowParams.packageName = mContext.packageName
    }
}